﻿using System;
using System.Windows;
using System.Windows.Media;

namespace Red.Toolkit.Profiler.Drawing
{
    public class TimeBar
    {
        private static void GetOptimalTimeStep( double timeScale, ref double timeStep, ref double blending )
        {
            timeScale *= 0.02;
            double tmp = -Math.Log10( timeScale );
            timeStep = Math.Floor( tmp );
            blending = 1.0 - (tmp - timeStep);
            timeStep = Math.Pow( 10.0, timeStep );
        }

        public static void DrawBackground( DrawingContext ctx, double w, double h, TimelineParams timelineParams, TimelineStyle style )
        {
            // time steps
            double timeStep = 0.0;
            double gridBlending = 0.0;
            GetOptimalTimeStep( timelineParams.PixelsPerSecond, ref timeStep, ref gridBlending );

            double bigTimeStep = timeStep * 10.0;
            double minDrawTime = Math.Floor( timelineParams.TimeOffset / bigTimeStep ) * bigTimeStep;
            double maxDrawTime = Math.Ceiling( (timelineParams.TimeOffset + w * timelineParams.SecondsPerPixel) / bigTimeStep ) * bigTimeStep;

            Color color = Color.FromArgb( (byte)(style.TimeBarColor.A * gridBlending),
                                         style.TimeBarColor.R,
                                         style.TimeBarColor.G,
                                         style.TimeBarColor.B );
            Brush tmpTimeBarBrush = new SolidColorBrush( color );
            Pen tmpTimeBarPen = new Pen( tmpTimeBarBrush, 1.0 );

            // draw the ticks
            int count = 0;
            for ( double x = minDrawTime; x <= maxDrawTime; x += timeStep, ++count )
            {
                if ( x < timelineParams.TimeRangeStart || x > timelineParams.TimeRangeEnd )
                    continue;

                double pixelX = (x - timelineParams.TimeOffset) * timelineParams.PixelsPerSecond;
                if ( count % 10 == 0 )
                    ctx.DrawLine( style.TimeBarPen, new Point( pixelX, 0 ), new Point( pixelX, h ) );
                else
                    ctx.DrawLine( tmpTimeBarPen, new Point( pixelX, 0 ), new Point( pixelX, h ) );
            }

            // time bar ranges
            {
                double startX = (timelineParams.TimeRangeStart - timelineParams.TimeOffset) * timelineParams.PixelsPerSecond;
                if ( startX > 0.0f )
                {
                    Rect rect = new Rect( 0, 0, startX, h );
                    ctx.DrawRectangle( style.TimeBarInvalidBrush, null, rect );
                }

                double endX = (timelineParams.TimeRangeEnd - timelineParams.TimeOffset) * timelineParams.PixelsPerSecond;
                if ( endX < w )
                {
                    Rect rect = new Rect( endX, 0, w, h );
                    ctx.DrawRectangle( style.TimeBarInvalidBrush, null, rect );
                }
            }
        }

        public static void DrawOverlay( DrawingContext ctx, double w, double h, TimelineParams timelineParams, TimelineStyle style )
        {
            // time steps
            double timeStep = 0.0;
            double gridBlending = 0.0;
            GetOptimalTimeStep( timelineParams.PixelsPerSecond, ref timeStep, ref gridBlending );

            double bigTimeStep = (timeStep * 10.0f);
            double minDrawTime = Math.Floor( timelineParams.TimeOffset / bigTimeStep ) * bigTimeStep;
            double maxDrawTime = Math.Ceiling( (timelineParams.TimeOffset + w * timelineParams.SecondsPerPixel) / bigTimeStep ) * bigTimeStep;

            // time bar background
            {
                Rect rect = new Rect( 0, h - style.TimeBarHeight, w, h );
                ctx.DrawRectangle( style.TimeBarBrush, null, rect );
            }

            // draw the ticks
            int count = 0;
            for ( double x = minDrawTime; x <= maxDrawTime; x += timeStep, ++count )
            {
                if ( x < timelineParams.TimeRangeStart || x > timelineParams.TimeRangeEnd )
                    continue;

                double pixelX = (x - timelineParams.TimeOffset) * timelineParams.PixelsPerSecond;
                Point start = new Point( pixelX, h - style.TimeBarHeight );
                Point end;

                if ( count % 10 != 0 )
                    end = new Point( pixelX, h - style.TimeBarHeight + style.TimeBarTickHeightSmall );
                else
                    end = new Point( pixelX, h );

                ctx.DrawLine( style.TimeBarTickPen, start, end );
            }

            // draw the time captions
            count = 0;
            for ( double x = minDrawTime; x <= maxDrawTime; x += timeStep, ++count )
            {
                if ( x < timelineParams.TimeRangeStart || x > timelineParams.TimeRangeEnd )
                    continue;

                double pixelX = (x - timelineParams.TimeOffset) * timelineParams.PixelsPerSecond;

                if ( count % 10 == 0 )
                {
                    string str = null;

                    if ( timeStep >= 1.0f )
                    {
                        int sec = (int)(Math.Abs( x )) % 60;
                        int min = (int)(x) / 60;
                        str = String.Format( "{0:00}:{1:00}", min, sec );
                    }
                    else if ( timeStep >= 1.0e-1 )
                        str = string.Format( "{0:0.0}", x );
                    else if ( timeStep >= 1.0e-2 )
                        str = string.Format( "{0:0.00}", x );
                    else if ( timeStep >= 1.0e-3 )
                        str = string.Format( "{0:0.000}", x );
                    else if ( timeStep >= 1.0e-4 )
                        str = string.Format( "{0:0.0000}", x );
                    else if ( timeStep >= 1.0e-5 )
                        str = string.Format( "{0:0.00000}", x );

                    if ( str != null )
                    {
                        FormattedText text = new FormattedText( str, style.CultureInfo,
                            FlowDirection.LeftToRight, style.TextTypeface, 11.0, style.TimeBarFontBrush );
                        ctx.DrawText( text, new Point( pixelX + 2,
                            h - style.TimeBarHeight + style.TimeBarTickHeightSmall + 2 ) );
                    }
                }
            }
        }
    }
}
